/**
 * @author syang4
 */
Class("QS.FileLoader.ModuleProfile",{
	has: {
		ready :{ is : 'rw', init : false },
		ID2Name:{ is : 'rw', init : Joose.I.Object },
		name2ID:{ is : 'rw', init : Joose.I.Object },
		moduleProfile:{ is : 'rw', init : Joose.I.Object},
		loadXMLConfig:{ is : 'rw', init : Joose.I.Object}
	},
	methods: {
		initialize:function(){
			var self = this;
			var autoInit=this.loadXMLConfig.autoInit===false?false:true;
			if(autoInit){
				var xmlURL=this.loadXMLConfig.xmlURL?this.loadXMLConfig.xmlURL:"js/sys/modulefiles.xml";
				$.get(xmlURL,function(o){
					self.parseConfig(o);
					self.ready = true;
				});
			}
		},
		parseConfig: function(o){
			var version = typeof(QS_VERSION) == "undefined" ? "release" : QS_VERSION;
			var dom = $(o).find('src[env="'+version+'"]');
			var meta = QS.FileLoader.my;
			meta.path = dom.attr('path');
			var modules = dom.find('module');
			for (var i = 0; i < modules.length; i++) {
				var module = $(modules[i]),
					id = module.attr('id'), 
					name = module.attr('name');
				
				var css = module.find('css');
				var js = module.find('js');
				
				css = css ? css.text().split(',') : [];
				js = js ? js.text().split(',') : [];
				
				this.addModule({
					id: id,
					name: name,
					profile: css.concat(js)
				});
			}
		},
		addModule:function(o){
			this.ID2Name[o["id"]] = o["name"];
			this.name2ID[o["name"]] = o["id"];
			this.moduleProfile[o["id"]] = o["profile"];
		}
	}
});

Class("QS.FileLoader.Module",{
	has: {
		id:{required : true, is : 'rw', init:null},
		name:{required : true, is : 'rw', init:null},
		fileList:{is : 'rw', init:[]},
		cssList:{is : 'rw', init:[]},
		jsList:{is : 'rw', init:[]},
		callback:{is : 'rw', init:null},
		
		jsReadyStatus:{is : 'rw', init:0},
		ready:{is : 'rw', init: false}
	},
	methods: {
		initialize:function(){
			this.jsList =[];
			this.cssList =[];
			this.callback = null;
			this.jsReadyStatus = 0;
			this.ready = false;
			
			if (this.fileList.length > 0) {
				for (var i = 0, l = this.fileList.length; i < l; i++) {
					var url = this.fileList[i];
					if (url.lastIndexOf('.js') == url.length - 3) {
						this.jsList.push(url);
					}
					if (url.lastIndexOf('.css') == url.length - 4) {
						this.cssList.push(url);
					}
				}
			}
		},
		_load:function(type,iteration){
			var self=this;
			var items=[],callFun=null;
			if(type=='JS'){
				items=this.jsList;
				callFun=function(){
					self.loadJS(items[iteration],function(){
						self._load(type,iteration+1);
					})
				}
			}else if(type=='CSS'){
				items=this.cssList;
				callFun=function(){
					self.loadCSS(items[iteration],function(){
						self._load(type,iteration+1);
					})
				}
			}
			if (!iteration) iteration = 0;
			if(items[iteration]&&typeof callFun=='function'){
				callFun();
			}
		},
		loadJS:function(url,callback){
			var self=this;
			var meta = QS.FileLoader.my;
			for(var p in meta.loadedJS){
				if(p == url || url == (meta.path + p).replace(/^http[s]?:/,'')){
					this.updateStatus('JS',url);
					return;
				}
			}
			var fileRef = document.createElement('script');
			fileRef.setAttribute("type", "text/javascript");
			fileRef.setAttribute("src", url);
			if(typeof callback=='function'){
				fileRef.onload=fileRef.onreadystatechange=function(){
					if(! this.readyState //FF did not caontains readyState
						|| this.readyState=='loaded' || this.readyState=='complete'){
						self.updateStatus('JS',url);
						callback();
					}
				}
			}
			document.getElementsByTagName("head")[0].appendChild(fileRef);
		},
		loadCSS:function(url,callback){
			//judge if have loaded
			var self=this;
			var meta = QS.FileLoader.my;
			for(var p in meta.loadedCSS){
				if(p == url || url == (meta.path + p).replace(/^http[s]?:/,'')){
					this.updateStatus('CSS',url);
					return;
				}
			}
			
			//load css
			var fileRef = document.createElement("link");
			fileRef.setAttribute("rel", "stylesheet");
			fileRef.setAttribute("type", "text/css");
			fileRef.setAttribute("href", url);
			if(typeof callback=='function'){
				fileRef.onload=fileRef.onreadystatechange=function(){
					if(! this.readyState //FF did not caontains readyState
						|| this.readyState=='loaded' || this.readyState=='complete'){
						self.updateStatus('CSS',url);
						callback();
					}
				}
			}
			document.getElementsByTagName("head")[0].appendChild(fileRef);
		},
		load:function(callback){
			this.callback = callback;
			if (this.ready) {
				this.onLoad();
			}
			else {
				this.jsReadyStatus = 0;
				this._load('JS');
				this._load('CSS');
				//this.loadCSS();
				//this.loadJS();
			}
		},
		_updateJSStatus:function(url){
			//add into loaded JS files list
			var meta = QS.FileLoader.my;
			if (!meta.loadedJS[url]) {
				meta.loadedJS[url] = true;
			}
			//if all js loaded, then will call the callback
			this.jsReadyStatus += 1;
			if(this.jsReadyStatus == this.jsList.length){
				this.ready = true;
				this.onLoad();
			}
		},
		_updateCSSStatus:function(url){
			//add into loaded JS files list
			var meta = QS.FileLoader.my;
			if (!meta.loadedCSS[url]) {
				meta.loadedCSS[url] = true;
			}
		},
		updateStatus:function(fileType,url){
			if(fileType=='JS'){
				this._updateJSStatus(url);
			}else if(fileType=='CSS'){
				this._updateCSSStatus(url);
			}
		},
		onLoad: function(){
			if(typeof Terminal!='undefined'&&typeof Terminal.hideLoading=='function'){
				Terminal.hideLoading();
			}
			this.ready = true, callback = this.callback;
			var fnType = typeof(callback);
			if (fnType == 'function') {
				callback(this);
			}else if (fnType == 'object') {
				if (callback.caller && callback.onInvoke && typeof(callback.onInvoke) == 'function') {
					callback.onInvoke.call(callback.caller, this);
				}else if (typeof(callback.onInvoke) == 'function') {
					callback.onInvoke(this);
				}
			}
		}
	}
});

Class("QS.FileLoader",{
	my:{
		has:{
			path:{is : 'rw', init: ""},
			loadedJS:{is : 'rw', init: Joose.I.Object},
			loadedCSS:{is : 'rw', init: Joose.I.Object}
		},
		
		methods: {
			initialize: function(){
				var css = $('link[type="text/css"]'),
					js = $('script[type="text/javascript"]');
				
				for (var i = 0; i < css.length; i++) {
					var url = css[i].getAttribute('href');
					if(url)this.loadedCSS[url] = true;
				}
				for (var i = 0; i < js.length; i++) {
					var url = js[i].getAttribute('src');
					if(url)this.loadedJS[url] = true;
				}
			}
		}
	},
	
	has:{
		modules:{is : 'rw', init: Joose.I.Object},
		loadXMLConfig:{is : 'rw', init: Joose.I.Object},
		moduleProfile:{is : 'rw', builder: "_buildModuleProfile"}
	},
	
	methods:{
		_buildModuleProfile: function(){
			return new QS.FileLoader.ModuleProfile({loadXMLConfig:this.loadXMLConfig});
		},
		LoadModule:function(module, callback){
			if(!this.moduleProfile.ready){
				var self = this;
				window.setTimeout(function(){
					self.LoadModule(module, callback);
				},500);
			}else{
				if(typeof(module)!='object'){
					throw new Error("Parameter 'module' must be an Object. eg:{id:'xxx', name:'XXX'}");
				}
				var oModule = null;
				var mProfile = this.moduleProfile;
				if (module["id"] || module["name"]) {
					var id = module["id"] = module["id"] || mProfile.name2ID[module["name"].toLowerCase()];
					var name = module["name"] = module["name"] || mProfile.ID2Name[module["id"].toLowerCase()];
					var filelist = module["fileList"] =  mProfile.moduleProfile[id];
					if (module["id"]) {
						if (typeof(filelist) != 'undefined') {
							if(this.modules[id]){
								oModule = this.modules[id];
							}else{
								oModule = new QS.FileLoader.Module(module);
								this.modules[id] = oModule;
							}	
						}else{
							console.warn("module '"+id+"' has no file list, please add them(including css and js) into 'QS.FileLoader.ModuleProfile.moduleProfile' in the file js/sys/modulefiles.xml");
						}
					}
					if(typeof Terminal!='undefined'&&typeof Terminal.showLoading=='function'){
						Terminal.showLoading();
					}
					oModule.load(callback);
				}	
			}
		},
		LoadFiles:function(urlList, callback){
			var id = this._Generate16BitRandomNumber(),
				name = id;
			var module = new QS.FileLoader.Module({
				id:id,
				name:name,
				fileList:urlList
			});
			if(typeof Terminal!='undefined'&&typeof Terminal.showLoading=='function'){
				Terminal.showLoading();
			}
			module.load(callback);
			this.modules[id] = module;
		},
		_Generate16BitRandomNumber: function(){
			var chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
			//var chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
			var res = "";
			for (var i = 0; i < 32; i++) {
				var id = Math.ceil(Math.random() * 15);
				res += (this._isSperaterPosition(i)? "-" : "") + chars[id];
			}
			return res;
		},
		_isSperaterPosition: function(pos){
			var number = pos/4;
			if (number == Math.floor(number) && number > 1 && number < 6) 
				return true;
			else
				return false
		}
	}
});